package com.intretech.tj.light;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intretech.tj.device.DeviceVerticle;
import com.intretech.tj.light.service.YamlService;
import com.intretech.tj.mqtt.MQTTVerticle;
import com.intretech.tj.mqtt.trigger.TopicMessageTrigger;
import com.intretech.tj.tcp.TCPVerticle;
import io.quarkus.scheduler.Scheduled;
import io.smallrye.mutiny.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.intretech.tj.global.parent.OutLogParent.JSONError;
import static com.intretech.tj.global.tools.HexTool.decimalToHexStr;
import static com.intretech.tj.global.tools.JSONTool.toJSONString;
import static com.intretech.tj.light.OutLog.*;

@Slf4j
@ApplicationScoped
public class LightVerticle extends AbstractVerticle {
    private final OutLog outLog;
    private final LightConfig config;

    private final TCPVerticle tcpVerticle;

    private final MQTTVerticle mqttVerticle;

    private final DeviceVerticle deviceVerticle;

    private final TopicMessageTrigger topicMessageTrigger;

    private final YamlService yamlService;

    @Setter
    @Getter
    private boolean refuseLight = false;

    Map<Integer, Light> lightMap = new ConcurrentHashMap<>();
    Map<Integer, Light> instructionLightMap = new ConcurrentHashMap<>();

    @Inject
    public LightVerticle(OutLog outLog, LightConfig config, TCPVerticle tcpVerticle, MQTTVerticle mqttVerticle,
                         DeviceVerticle deviceVerticle, TopicMessageTrigger topicMessageTrigger, YamlService yamlService) {
        this.outLog = outLog;
        this.config = config;
        this.tcpVerticle = tcpVerticle;
        this.mqttVerticle = mqttVerticle;
        this.deviceVerticle = deviceVerticle;
        this.topicMessageTrigger = topicMessageTrigger;
        this.yamlService = yamlService;
    }

    @Override
    public void start(Promise<Void> startPromise) {
        for (int id : config.defaultReds()) {
            if (id == 0)
                continue;
            lightMap.put(id, new Light(id, State.RED, config.defaultRed(), config.defaultRed(), config.defaultGreen(),
                    config.defaultYellow()));
        }
        for (int id : config.defaultGreens()) {
            if (id == 0)
                continue;
            lightMap.put(id, new Light(id, State.GREEN, config.defaultGreen(), config.defaultRed(),
                    config.defaultGreen(), config.defaultYellow()));
        }
        for (int id : config.defaultYellows()) {
            if (id == 0)
                continue;
            lightMap.put(id, new Light(id, State.YELLOW, config.defaultYellow(), config.defaultRed(),
                    config.defaultGreen(), config.defaultYellow()));
        }
        //持久化存储红绿灯
        if (yamlService.saveIfNotExists("light.yaml")) {
            // 红绿灯已被修改
            lightMap.clear();
            instructionLightMap.clear();
            Light[] editLight = yamlService.loadFromYaml("light.yaml", Light[].class);
            for (Light light : editLight) {
                lightMap.put(light.getId(), light);
            }
        } else {
            // 默认文件导出
            ArrayList<Light> lightArrayList = new ArrayList<>(lightMap.values());
            yamlService.saveAsYaml(lightArrayList, "light.yaml");
        }

        // 如果启用mqtt
        if (config.run().equalsIgnoreCase("mqtt")) {
            lightMap.values().forEach(light -> {
                // 启动时初始化发布
                mqttVerticle.retain(config.MQTTPublishTopic() + light.getId(), 0, toJSONString(light));
                // 监听主题，同步红绿灯数据
                topicMessageTrigger.setTrigger(config.ListenTopic() + light.getId(), outLog.getServerName(),
                        (idAndMessage) -> {
                            ObjectMapper objectMapper = new ObjectMapper();
                            try {
                                Light newLight = objectMapper.readValue(idAndMessage.message().payload().toString(),
                                        Light.class);
                                update(newLight);
                                deviceVerticle.update(newLight.toDevice());
                                mqttVerticle.retain(config.AllDataTopic(), 0, toJSONString(lightMap.values()));
                            } catch (JsonProcessingException e) {
                                log.error(outLog.getMessage(JSONError));
                            }
                        });
            });
        }


        // 监听修改主题，更新红绿灯
        topicMessageTrigger.setTrigger(config.MQTTUpdateTopic(), outLog.getServerName(), (idAndMessage) -> {
            setRefuseLight(true);
            lightMap.clear();
            instructionLightMap.clear();
            Light[] editLight = yamlService.loadFromYaml("light.yaml", Light[].class);
            for (Light light : editLight) {
                lightMap.put(light.getId(), light);
            }
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                Light newLight = objectMapper.readValue(idAndMessage.message().payload().toString(), Light.class);
                update(newLight);
                mqttVerticle.retain(config.MQTTPublishTopic() + newLight.getId(), 0, toJSONString(newLight));
                deviceVerticle.update(newLight.toDevice());
            } catch (JsonProcessingException e) {
                log.error(outLog.getMessage(JSONError));
            }

            setRefuseLight(false);
        });


        // 新增：监听器用于修改红绿灯信息 (只接收 ID 和目标颜色)
        if (config.run().equalsIgnoreCase("mqtt")) {
            topicMessageTrigger.setTrigger(config.MQTTModifyTopic(), outLog.getServerName(), (idAndMessage) -> {
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    List<LightRequest> list = objectMapper.readValue(idAndMessage.message().payload().toString(),
                            new TypeReference<List<LightRequest>>() {
                            });
                    for (LightRequest lightRequest : list) {
                        int lightId = lightRequest.getId();
                        State targetState = lightRequest.getState();

                        Light originalLight = lightMap.get(lightId);
                        if (originalLight != null) {
                            // 创建一个新的 Light 对象，基于原始配置，但修改状态和时间
                            Light modifiedLight = new Light(
                                    originalLight.getId(),
                                    targetState,
                                    999,
                                    originalLight.getRedTime(),
                                    originalLight.getGreenTime(),
                                    originalLight.getYellowTime()
                            );
                            instructionLightMap.put(lightId, modifiedLight);
                            log.info(outLog.getMessage("成功将红绿灯 {} 的状态修改为 {}", lightId, targetState.name()));
                        } else {
                            log.warn(outLog.getMessage("未找到ID为 {} 的红绿灯，无法修改。", lightId));
                        }
                    }
                } catch (JsonProcessingException e) {
                    log.error(outLog.getMessage(JSONError), e);
                } catch (NullPointerException e) {
                    log.error(outLog.getMessage("接收到的修改消息格式不正确，缺少 'id' 或 'color' 字段。"), e);
                }
            });

            // 新增：监听器用于恢复红绿灯信息 (只接收 ID)
            topicMessageTrigger.setTrigger(config.MQTTRecoverTopic(), outLog.getServerName(), (idAndMessage) -> {
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    JsonNode rootNode = objectMapper.readTree(idAndMessage.message().payload().toString());
                    List<Integer> idList = new ArrayList<>();

                    if (rootNode.isArray()) {
                        for (JsonNode node : rootNode) {
                            int id = node.get("id").asInt();
                            if (instructionLightMap.containsKey(id)) {
                                instructionLightMap.remove(id);
                            } else {
                                log.warn(outLog.getMessage("红绿灯 {} 不在指令映射中，无需恢复。", id));
                            }
                            idList.add(id);
                        }
                    }
                    // 打印验证
                    log.info(outLog.getMessage("红绿灯 {} 已从指令映射中移除，恢复为默认设置。", idList));
                } catch (JsonProcessingException e) {
                    log.error(outLog.getMessage(JSONError), e);
                } catch (NullPointerException e) {
                    log.error(outLog.getMessage("接收到的恢复消息格式不正确，缺少 'id' 字段。"), e);
                }
            });
        }
    }

    /**
     * MQTT
     */
    @Scheduled(every = "1s")
    void syncMqttLight() {
        if (config.run().equalsIgnoreCase("mqtt")) {
            mqttVerticle.retain(config.AllDataTopic(), 0, toJSONString(lightMap.values()));
        }

    }

    /**
     * TCP红绿灯刷新函数
     */
    @Scheduled(every = "1s")
    void refresh() {
        if (config.run().equalsIgnoreCase("mqtt") && !isRefuseLight()) {
            StringBuilder builder = new StringBuilder();
            // 刷新并生成消息
            lightMap.values().forEach(light -> {
                int id = light.getId();
                int time = light.getTime();
                State state = light.getState();
                if (time <= 1) {
                    switch (state) {
                        case RED -> {
                            state = State.GREEN;
                            time = light.getGreenTime();
                        }
                        case GREEN -> {
                            state = State.YELLOW;
                            time = light.getYellowTime();
                        }
                        case YELLOW -> {
                            state = State.RED;
                            time = light.getRedTime();
                        }
                    }
                } else
                    time--;
                light.setTime(time);
                light.setState(state);
                String msg = getMessage(id, state.value, time);
                builder.append(msg);
                deviceVerticle.update(light.toDevice());

                mqttVerticle.retain(config.ListenTopic() + light.getId(), 0, toJSONString(instructionLightMap.getOrDefault(id, light)));

                log.debug(outLog.getMessage(Refresh, id, state, time, msg));
            });
            mqttVerticle.retain(config.AllDataTopic(), 0, toJSONString(lightMap.values()));
//            try {
//                tcpVerticle.send(config.TCPAddress(), builder.toString());
//            } catch (IPErrorException e) {
//                mqttVerticle.publish(config.error(), 0,
//                        toJSONString(new MessageData("all", Type.Light, Error, getNowTime())));
//            }
        }
    }

    /**
     * 根据红绿灯属性生成消息
     *
     * @param id    红绿灯id
     * @param state 红绿灯状态值
     * @param time  红绿灯剩余时间
     * @return 协议消息
     */
    private String getMessage(int id, int state, int time) {
        return config.TCPMessage().formatted(
                decimalToHexStr(id),
                decimalToHexStr(state),
                decimalToHexStr(state),
                decimalToHexStr(state),
                decimalToHexStr(state),
                decimalToHexStr(time));
    }

    private void update(Light light) {
        if (lightMap.containsKey(light.getId())) {
            lightMap.put(light.getId(), light);
        }
    }
}